package cn.leida.ruoyi.framework.jpa.tools;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.leida.common.field.bean.JavaFieldBean;
import cn.leida.common.field.bean.JavaFieldTotal;
import cn.leida.common.field.util.ClassFieldUtil;
import cn.leida.common.field.util.JavaFieldUtil;
import cn.leida.common.field.util.JavaJsonSqlFieldUtil;
import cn.leida.common.field.util.JavaTypeUtil;
import cn.leida.common.sql.table.bean.JavaTableSqlBean;
import cn.leida.ruoyi.common.utils.poi.ExcelAnnotationUtil;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lei
 * @create 2025-03-11 21:44
 */
public class JPAJavaFieldUtil {

    /**
     * 1. 忽略 Transient (jpa注解)
     * 2. 忽略 BaseEntity 属性
     */
    public static List<JavaFieldBean> jpaJavaFieldBeans(Class<?> clazz) {
        List<JavaFieldBean> fieldBeans = jpaJavaFieldList(clazz);
        // 更新excel注解
        JavaJsonSqlFieldUtil.updateFieldName(fieldBeans, ExcelAnnotationUtil.excelNameMap(clazz));
        // sqlGroup
        JavaJsonSqlFieldUtil.updateSqlGroupMap(fieldBeans, ClassFieldUtil.sqlTotalMap(clazz));
        return fieldBeans;
    }

    public static List<JavaFieldTotal> fieldGroupList(Class<?> clazz) {
        List<JavaFieldBean> fieldBeans = jpaJavaFieldBeans(clazz);
        List<JavaFieldTotal> groupList = new ArrayList<>();
        fieldBeans.forEach(e -> {
            JavaFieldTotal group = new JavaFieldTotal();
            BeanUtil.copyProperties(e, group);
            groupList.add(group);
        });

        return groupList;
    }

    public static JavaTableSqlBean javaTableSql(Class<?> beanClazz, String tableNameCn) {
        JavaTableSqlBean sqlBean = new JavaTableSqlBean();
        // 表名: t_user
        sqlBean.setTableName(JPAJavaFieldUtil.tableName(beanClazz));
        // 中文表名: 用户
        sqlBean.setTableNameCN(tableNameCn);
        return sqlBean;
    }


    /**
     * 读取class所有 JavaField
     * 1. 忽略 Transient (jpa注解)
     * 2. 忽略 BaseEntity 属性
     */
    private static List<JavaFieldBean> jpaJavaFieldList(Class<?> clazz) {
        List<JavaFieldBean> fieldBeans = new ArrayList<>();
        // 所有属性
        Field[] fields = ReflectUtil.getFields(clazz);
        if (fields != null) {
            for (Field field : fields) {
                if (JavaFieldUtil.isStatic(field)) {
                    continue;
                }
                JavaFieldBean javaField = JavaFieldUtil.javaField(field);

                // jpa 忽略字段
                Transient tran = field.getAnnotation(Transient.class);
                if (tran != null) {
                    continue;
                }
                // jpa 字段信息
                Column column = field.getAnnotation(Column.class);
                if (column != null) {
                    javaField.setSqlField(column.name());
                    // 字符串长度
                    if (JavaTypeUtil.stringType(javaField.getJavaType())) {
                        javaField.setSqlLength(column.length());
                    } else {
                        javaField.setSqlLength(0);
                    }
                }
                // 重新初始化:
                javaField.initBean();
                fieldBeans.add(javaField);
            }
        }
        return fieldBeans;
    }


    /**
     * sql 字段信息
     */
    public static Map<String, String> columnNameMap(Class<?> clazz) {
        Map<String, String> beanAliasMap = new LinkedHashMap<>();
        Field[] fields = ReflectUtil.getFields(clazz,
            field -> field.isAnnotationPresent(Column.class));
        if (fields != null) {
            for (Field field : fields) {
                if (JavaFieldUtil.isStatic(field)) {
                    continue;
                }
                Column column = field.getAnnotation(Column.class);
                if (column != null && StrUtil.isNotBlank(column.name())) {
                    beanAliasMap.put(field.getName(), column.name().trim());
                }
            }
        }
        return beanAliasMap;
    }

    /**
     * java字段: userName
     */
    public static String idJavaField(Class<?> clazz) {
        return idField(clazz, true);
    }

    /**
     * 根据注解获取 表名
     */
    public static String tableName(Class<?> beanClazz) {
        Table table = AnnotationUtil.getAnnotation(beanClazz, Table.class);
        if (table != null) {
            return table.name();
        } else {
            return StrUtil.toUnderlineCase(beanClazz.getSimpleName());
        }
    }

    /**
     * sql字段: user_name
     */
    public static String idSqlField(Class<?> clazz) {
        return idField(clazz, false);
    }

    /**
     * sql 字段信息
     */
    public static String idField(Class<?> clazz, boolean javaField) {
        Map<String, String> beanAliasMap = new LinkedHashMap<>();
        Field[] fields = ReflectUtil.getFields(clazz,
            field -> field.isAnnotationPresent(Id.class));
        if (fields != null) {
            for (Field field : fields) {
                if (JavaFieldUtil.isStatic(field)) {
                    continue;
                }
                Id id = field.getAnnotation(Id.class);
                if (id != null) {
                    if (javaField) {
                        return field.getName();
                    }
                    Column column = field.getAnnotation(Column.class);
                    if (column != null && StrUtil.isNotBlank(column.name())) {
                        return column.name().trim();
                    }
                }

            }
        }
        return "id";
    }


    public static void printGroupCode(Class<?> clazz) {
        List<JavaFieldTotal> sqlFieldList = fieldGroupList(clazz);
        for (JavaFieldTotal fieldCode : sqlFieldList) {
            String sqlGroupCode = fieldCode.totalSqlCode();
            if (StrUtil.isNotBlank(sqlGroupCode)) {
                System.out.println(sqlGroupCode);
            }
        }
        System.out.println();
        for (JavaFieldTotal fieldCode : sqlFieldList) {
            String sqlGroupCode = fieldCode.groupJavaFiledCode();
            if (StrUtil.isNotBlank(sqlGroupCode)) {
                System.out.println(fieldCode.aliasCode());
                System.out.println(sqlGroupCode);
            }
        }
    }
}
